package com.zuipin.service.impl;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.zuipin.entity.DrawNum;
import com.zuipin.entity.shoppingCart.RuleSet;
import com.zuipin.entity.shoppingCart.RuleType;
import com.zuipin.entity.shoppingCart.Status;
import com.zuipin.framework.emuns.ErrorCode;
import com.zuipin.framework.exception.CustomException;
import com.zuipin.framework.result.Result;
import com.zuipin.mapper.DrawNumMapper;
import com.zuipin.service.IDrawNumService;
import com.zuipin.service.IMemberAccountService;
import com.zuipin.service.IRuleSetService;
import com.zuipin.util.ConstantsUtil;
import com.zuipin.util.DateUtils;
import com.zuipin.util.RedisUtils;
import com.zuipin.vo.DistributeResultVo;
import com.zuipin.vo.SendRedPacketResult;

/**
 * @ClassName: DrawLevelGroupServiceImpl
 * @author xujinding
 * @time 2017年3月27日下午4:02:26
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class DrawNumImpl implements IDrawNumService {
	
	@Resource
	private DrawNumMapper			drawNumMapper;
	
	@Resource
	private IMemberAccountService	memberAccountService;
	
	@Resource
	private IRuleSetService			ruleSetService;
	@Resource
	private RedisUtils				redisUtils;
	private final Logger			log	= LoggerFactory.getLogger(getClass());
	
	/**
	 * 修改抽奖次数
	 * @param memberId
	 * @param ruleId
	 * @param sysId
	 * @param num
	 * @return   结果次数
	 */
	public Integer modityDrawNum(Long memberId, Long ruleId, Long sysId, Integer num, Long sysUserId) {
		DrawNum dn = new DrawNum();
		dn.setSysId(sysId);
		dn.setMemberId(memberId);
		dn.setRuleId(ruleId);
		dn.setDelFlag(ConstantsUtil.DEL_FLAG_NO_0);
		// List<DrawNum> drawNums = drawNumMapper.findBySelective(dn);
		List<DrawNum> drawNums = drawNumMapper.findBySelectiveForUpdate(dn);
		if (drawNums != null && drawNums.size() > 0) {
			DrawNum drawNum = drawNums.get(0);
			// drawNum.setUpdateId(sysUserId);
			// drawNum.setUnUseNum(drawNum.getUnUseNum() + num);
			// drawNumMapper.updateByPrimaryKeySelective(drawNum);
			// dn.setMemberId(memberId);
			// dn.setRuleId(ruleId);
			// dn.setDelFlag(ConstantsUtil.DEL_FLAG_NO_0);
			drawNum.setUnUseNum(num);
			drawNumMapper.modityDrawNum(drawNum);
			return drawNum.getUnUseNum();
		} else {
			dn.setCreateId(sysUserId);
			dn.setUpdateId(sysUserId);
			dn.setUnUseNum(num);
			drawNumMapper.insertSelective(dn);
			return dn.getUnUseNum();
		}
	}
	
	/**
	 * 修改抽奖次数
	 * @param memberId
	 * @param ruleId
	 * @param sysId
	 * @param num
	 * @return   结果次数
	 */
	public int modityDrawNumLock(Long memberId, Long ruleId, Long sysId, Integer num, Long sysUserId) {
		DrawNum dn = new DrawNum();
		dn.setSysId(sysId);
		dn.setMemberId(memberId);
		dn.setRuleId(ruleId);
		dn.setDelFlag(ConstantsUtil.DEL_FLAG_NO_0);
		dn.setUnUseNum(num);
		return drawNumMapper.modityDrawNumLock(dn);
		// List<DrawNum> drawNums = drawNumMapper.findBySelective(dn);
	}
	
	/**
	 * 根据系统Id，会员Id ，规则Id查询抽奖次数
	 * @param memberId
	 * @param ruleId
	 * @param sysId
	 * @return
	 */
	public DrawNum findDrawNum(Long memberId, Long ruleId, Long sysId, String device) {
		DrawNum dn = new DrawNum();
		dn.setSysId(sysId);
		dn.setDevice(device);
		dn.setMemberId(memberId);
		dn.setRuleId(ruleId);
		dn.setDelFlag(ConstantsUtil.DEL_FLAG_NO_0);
		List<DrawNum> drawNum = drawNumMapper.findBySelective(dn);
		if (drawNum != null && drawNum.size() > 0) {
			return drawNum.get(0);
		}
		return null;
	}
	
	/**
	 * 根据系统Id，会员Id ，规则Id判断能不能抽奖
	 */
	@Override
	public boolean isCanDraw(Long memberId, Long ruleId, Long sysId) {
		DrawNum dn = this.findDrawNum(memberId, ruleId, sysId, null);
		if (dn != null && dn.getUnUseNum() != null && dn.getUnUseNum() > 0) {
			System.out.println(dn.getUnUseNum());
			return true;
		}
		return false;
	}
	
	/**
	 * 检查抽奖规则
	 * @param ruleSet
	 * @param sysId
	 * @throws CustomException
	 * @throws ParseException
	 */
	public void checkDrawNum(RuleSet ruleSet, Long sysId) throws CustomException, ParseException {
		if (ruleSet == null || !(ruleSet.getSysId().equals(sysId)) || !(RuleType.DRAW.toString().equals(ruleSet.getRuleType()))) {
			throw new CustomException(ErrorCode.RULE_NULL.getCode(), "查无规则");
		}
		if (!(Status.ALR_ENABLE.toString().equals(ruleSet.getStatus()))) {
			throw new CustomException(ErrorCode.RULE_STATUS_NO_ENABLE.getCode(), "规则未激活");
		}
		
		if ((new Date().getTime()) > DateUtils.parseFullTime(ruleSet.getEndTime()).getTime()) {
			throw new CustomException(ErrorCode.RULE_OUT_TIME.getCode(), "该活动已经结束");
		}
	}
	
	/**
	 * 派发抽奖次数
	 * @throws CustomException 
	 * @throws ParseException 
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Result<DistributeResultVo> toSendDrawNum(Long sysUserId, Long sysId, Long ruleSetId, Short isMemberLevel, String acceptor, Integer num)
			throws CustomException, ParseException {
		boolean isExist = redisUtils.exists("sendDrawNum");
		if (isExist) {
			throw new CustomException(ErrorCode.DB_EXCEPTION.getCode(), "有进程正在努力派发次数中，请稍等重试");
		}
		RuleSet ruleSet = ruleSetService.findRuleById(ruleSetId);
		this.checkDrawNum(ruleSet, sysId); // 检查规则
		Long successNums = 0L;// 派发成功数量
		Long failNums = 0L;// 派发失败数量
		StringBuffer failPhone = new StringBuffer();// 派发失败手机号码
		Map<String, Object> searchMap = new HashMap<>();
		searchMap.put("sysId", sysId);
		String[] acceptorArg = acceptor.split(ConstantsUtil.COMMA);
		
		if (acceptorArg != null && acceptorArg.length > 0) {
			if (SendRedPacketResult.SEND_MEMBER_LEVEL_YES_1 == isMemberLevel) {
				searchMap.put("memberLevels", acceptorArg);
			} else {
				searchMap.put("phones", acceptorArg);
			}
			// 电话号码 存在手机号不存在而失败的情况 等级不会失败
			List<Map<String, Object>> acceptorList = memberAccountService.searchSendMember(searchMap);
			if (RuleSet.SEND_BY_PHONE_EMAIL == isMemberLevel) {
				
				// 拼map --有电话的 会成功的
				Map<String, String> phoneMap = new HashMap<>();// 成功的电话map
				List<Long> memberList = new ArrayList<Long>();
				for (Map<String, Object> map : acceptorList) {
					Long memberId = Long.valueOf(String.valueOf(map.get("memberId")));
					memberList.add(memberId);
					// this.modityDrawNum(memberId, ruleSetId, sysId, num, sysUserId);
					if (map.get("mobilePhone") != null) {
						phoneMap.put(String.valueOf(map.get("mobilePhone")), "111");
					}
				}
				
				// 数组去重
				List<String> list = new LinkedList<String>();
				for (int i = 0; i < acceptorArg.length; i++) {
					if (!list.contains(acceptorArg[i])) {
						list.add(acceptorArg[i]);
					}
				}
				String[] newAcceptorArg = (String[]) list.toArray(new String[list.size()]);
				
				// 如果是按照手机号来派发会存在--手机号找不到而失败，，记录失败的手机号
				for (int i = 0; i < newAcceptorArg.length; i++) {
					String tempPhone = newAcceptorArg[i];
					if (phoneMap.get(tempPhone) == null) {
						failNums++;
						if (i == newAcceptorArg.length - 1) {
							failPhone.append(tempPhone);
						} else {
							failPhone.append(tempPhone).append(",");
						}
						
					}
				}
				if (memberList != null && memberList.size() > 0) {
					drawNumMapper.updateDrawNumByMemberId(sysId, memberList, ruleSetId, num, sysUserId);
					drawNumMapper.insertDrawNumLevelByMemberId(sysId, memberList, ruleSetId, num, sysUserId);
				}
				successNums = Long.valueOf(memberList.size());
				
			} else {
				if (acceptorList != null && acceptorList.size() > 0) {
					// 速度太慢 开个线程
					new Thread(new Runnable() {
						public void run() {
							try {
								log.info("根据会员等级派发--开始");
								redisUtils.set("sendDrawNum", "true", 60);
								drawNumMapper.updateDrawNumLevel(sysId, acceptorArg, ruleSetId, num, sysUserId);
								drawNumMapper.insertDrawNumLevel(sysId, acceptorArg, ruleSetId, num, sysUserId);
								boolean isExist = redisUtils.exists("sendDrawNum");
								if (isExist) {
									redisUtils.del("sendDrawNum");
								}
								log.info("根据会员等级派发--结束");
							} catch (Exception e) {
								log.info("根据会员等级派发抽奖次数失败:{},参数{}", e.getMessage(), acceptor);
							}
						}
					}).start();
					successNums = Long.valueOf(acceptorList.size());
				} else {
					successNums = 0L;
				}
				
			}
		}
		
		DistributeResultVo drv = new DistributeResultVo();
		drv.setFailNums(failNums);// 等级不会失败
		drv.setSuccessNums(successNums);
		drv.setFailPhone(failPhone.toString());
		Result<DistributeResultVo> res = new Result<>();
		res.setData(drv);
		res.setErrorCode(ErrorCode.SUCCESS);
		return res;
	}
	
	/**
	 * @throws CustomException  
	 * @Title: findDrawNumBySerNum 
	 * @Description: 根据序列号查询抽奖次数
	 * @author xujinding
	 * @param @param memberId
	 * @param @param serialNumber
	 * @param @param sysId
	 * @param @param device
	 * @param @return
	 * @throws 
	 */
	@Override
	public DrawNum findDrawNumBySerNum(Long memberId, String serialNumber, Long sysId, String device) throws CustomException {
		RuleSet rs = ruleSetService.selectBySerialNumber(serialNumber);
		if (rs == null) {
			throw new CustomException(ErrorCode.NOT_FIND.getCode(), "查无抽奖规则");
		}
		DrawNum dn = this.findDrawNum(memberId, rs.getId(), sysId, null);
		return dn;
	}
	
}